import tushare as ts
import time, datetime
import operator
import pandas
def getRounds(num):
    return round(num,3)
# 定义日期转换为星期的函数
def get_week_day(date):
    week_day_dict = {
        0: '星期一',
        1: '星期二',
        2: '星期三',
        3: '星期四',
        4: '星期五',
        5: '星期六',
        6: '星期天',
    }
    day = date.weekday()
    return week_day_dict[day]
#定义一个基金收益类
class fundProfit:
    # 投资方式
    invModel = ''
    # 每次投入金额
    everyMoney = 0
    # 总投入
    totalInvestment = 0
    # 收益
    profit = 0
    # 期数
    numberPeriods = 0
    # 总份额
    totalShare = 0
    # 卖出总金额
    lastProfit = 0
    # 每周的周几
    weekday = ''
    # 每月的几号
    chooseDay = ''
    def __str__(self):
        if(self.invModel == '每日定投'):
            msg = str(self.invModel) + str(self.everyMoney) + '共'+str(self.numberPeriods)+'期，共计投入金额为'+str(self.totalInvestment)+'，卖出总金额为'+str(self.lastProfit)+',利润为'+str(self.profit)
            return msg
        elif(self.invModel == '每周定投'):
            msg = str(self.invModel) +'，每周的'+str(self.chooseDay)+'投入'+ str(self.everyMoney) + '共' + str(self.numberPeriods) + '期，共计投入金额为' + str(self.totalInvestment) + '，卖出总金额为' + str(self.lastProfit) + ',利润为' + str(self.profit)
            return msg
        else:
            msg = str(self.invModel) + '，每月的' + str(self.chooseDay) + '号投入' + str(self.everyMoney) + '共' + str(self.numberPeriods) + '期，共计投入金额为' + str(self.totalInvestment) + '，卖出总金额为' + str(self.lastProfit) + ',利润为' + str(self.profit)
            return msg
    # def __str__(self,week):
    #     msg = str(self.invModel) + str(self.chooseDay) + str(self.profit)
    #     return  msg
    # def __str__(self,month):
    #     msg = str(self.invModel) + str(self.chooseDay) + str(self.profit)
    #     return  msg

def getData(ts_code, startDate, endDate):
    ts.set_token("531f7eda35d265a43c7091a5971802aab320a80c16afb6e7164c595a")
    # 链接应用数据接口
    pro = ts.pro_api()
    df = pro.fund_daily(ts_code=ts_code, start_date=startDate, end_date=endDate)
    print('搜索代码..', ts_code, '时间为：开始时间:', startDate, '结束时间', endDate)
    # print(df.shape[0])
    return df


def dayModel(EveryMoney):

    obj = fundProfit()
    # 每日定投
    obj.invModel = '每日定投'
    obj.everyMoney = EveryMoney
    fene_list = []  # 定义一个份额的列表1
    for i in range(0, len(trade_date)):  # 遍历整个数据
        fene_list.append(EveryMoney / close[i])  # 把每天的份额都存到份额列表中（每天定投金额 / 每天盘口关闭的价格）
    final_price = close[len(close) - 1]  # 从数据中取出最后一天的价格
    total_fene = round(sum(fene_list), 3)  # 总的份额pandaspandas

    obj.totalShare = getRounds(total_fene)
    # 期数
    obj.numberPeriods = str(len(close))
    # 共计投入
    obj.totalInvestment = str(len(trade_date) * EveryMoney)
    # 收益为
    obj.profit =getRounds(final_price * total_fene - len(trade_date) * EveryMoney)
    # 卖出总金额
    obj.lastProfit = getRounds(final_price * total_fene)
    return obj

    # 每周定投
def weekModel(EveryMoney,EveryData):


    obj = fundProfit()

    obj.invModel = '每周定投'

    obj.everyMoney = EveryMoney

    date_list = []  # 定义一个保存每周取出来的日期的列表

    fene_list = []  # 定义一个份额的列表

    EveryDataDic = {'1': "星期一", '2': "星期二", '3': "星期三", '4': "星期四", '5': "星期五"}

    weekDay = EveryDataDic[str(EveryData)]

    obj.chooseDay = weekDay

    for i in range(0, len(trade_date)):  # 遍历整个数据

        # 把数据中的日期转换为星期

        startData = trade_date[i]

        startTime = datetime.datetime.strptime(startData, '%Y%m%d').date()

        # 判断是否遍历的日期与循环的星期一致，如果是就选取日期，添加份额

        if (get_week_day(startTime) == weekDay):
            date_list.append(startData)  # 标记选取的日期

            fene_list.append(EveryMoney / close[i])  # 添加每期的份额

            final_price = close[i]  # 选取最后一次的价格作为出盘价格， 每次都会选取 但都会被覆盖
    # 期数
    obj.numberPeriods = str(len(date_list))
    # 共计投入
    obj.totalInvestment = len(date_list) * EveryMoney
    # 总份额
    obj.totalShare = getRounds(sum(fene_list))
    # 卖出总金额
    obj.lastProfit = getRounds(final_price * sum(fene_list))
    # 收益
    obj.profit = getRounds(final_price * sum(fene_list) - len(date_list) * EveryMoney)

    return obj


    # 每月定投
def monthModel(EveryMoney,day):


    obj = fundProfit()

    obj.invModel = '每月定投'

    obj.everyMoney = EveryMoney

    date_list = []  # 定义一个每次选取日期的存放列表

    fene_list = []  # 定义每次选取日子的份额数列表

    if (day < 10):
        monthDay = '0'+str(day)

    else:
        monthDay = str(day)

    obj.chooseDay = day
    # 遍历整个数据
    for i in range(0, len(trade_date)):

        if (trade_date[i][6:8] == monthDay):  # 截取的日期字符串的后面两位如果等于循环的日期就选取日期

            date_list.append(trade_date[i])  # 从数据日期中选出具体日期的时间，放入标记日期列表中

            fene_list.append(EveryMoney / close[i]) # 将每次想选取的日期的份额放入份额列表中

            final_price = close[i] # 每次都获取到开盘的价格，但是会被最后一次覆盖

    # 期数
    obj.numberPeriods = len(date_list)
    # 共计投入
    obj.totalInvestment = len(date_list) * EveryMoney
    # 总份额
    obj.totalShare = getRounds(sum(fene_list))
    # 卖出总金额
    obj.lastProfit =getRounds( final_price * sum(fene_list))
    # 收益
    obj.profit =getRounds(final_price * sum(fene_list) - len(date_list) * EveryMoney)

    return obj


# 选择要定投的类型
# print("1：每日定投")
# print("2：每周定投")
# print("3: 每月定投")

ts_code= str(input("请输入要查询的基金 (例如:150018.SZ):"))
startDate = str(input("请输入要查询的开始日期 (例如：20180101):"))
endDate = str(input("请输入要查询的截至日期 (例如：20200930):"))
ty= int (input("请选择 1 自定义日期定投方式 or 2 一键捕获最优方式："))
EveryMoney = float(input("请输入每次定投的金额："))

#如果选择自定义日期定投方式
if(ty == 1):
    print("自定义日期定投方式")

    # 掉哟个获取数据的函数
    df = getData(ts_code, startDate, endDate)
    # 把获取到的数据取出close（关闭交易市场的价格）这一列
    close = df['close']

    # 获取数据中日期一列
    trade_date = df['trade_date']

    # 选择要定投的类型
    # print("1：按日选择日期")
    print("2：按周选择日期")
    print("3: 按月选择日期")
    selfType = int(input("请输入要选择方式:"))
    if(selfType == 2):

        weekNum = int(input("请选择每周周几定投:"))

        #调用周定投的函数
        weekObje = weekModel(EveryMoney,weekNum)

        #对象中重写了 转换为str的函数，所以可以直接输出
        print(weekObje)
    elif(selfType == 3):

        monthNum = int(input("请选择每月几号定投"))

        #调用月定投的函数
        monthObj = monthModel(EveryMoney,monthNum)
        # 对象中重写了 转换为str的函数，所以可以直接输出
        print(monthObj)


        #这里是想实现 用户可以选择一周多天，一月多日，实验中。。。。

        # print("请问您一周选择几天")
        # n = int(input("请问您一周选择几天:"))
        #
        # weekObjList = []
        #
        # EveryDataDic = {'1': "星期一", '2': "星期二", '3': "星期三", '4': "星期四", '5': "星期五"}
        #
        # if(n== 5):
        #     DayinvModel = dayModel(EveryMoney)
        #
        # elif(n >0 and n<5):
        #     for i in range(1,n+1):
        #
        #         print("请选择第"+i+"天")
        #
        #         weekObjList.append(weekModel(EveryMoney,i))
        #
        # objSelf = fundProfit()
        # objSelf.invModel ='每周择日定投'
        # objSelf.everyMoney = EveryMoney
        # for i in range(0,len(weekObjList)):
        #     objSelf.totalShare  +=  weekObjList[i].totalShare
        #     objSelf.profit  += weekObjList[i].profit
        #     objSelf.numberPeriods += weekObjList[i].numberPeriods
        #     objSelf.totalShare = weekObjList[i].totalShare

# 如果用户选择意见不获
elif(ty == 2):
    print("您选择了一键捕获最优方式")

    df = getData(ts_code, startDate, endDate)
    # 把获取到的数据取出close（关闭交易市场的价格）这一列
    close = df['close']

    trade_date = df['trade_date']

    #定义一个空对象列表，来存放后面获取到的对象
    allIObjList = []

    #每日定投
    DayinvModel = dayModel(EveryMoney)

    #获取按周定投的最大利率方式
    weekObjList = []
    #从周一到周五，每次都去调用周定投函数都返回对应的对象
    for i in range(1,6):

        weekObjList.append(weekModel(EveryMoney,i))

    #通过 profit来比较他们并排序
    cmpfun = operator.attrgetter('profit', 'numberPeriods')

    # 用cmpfun来从小到大排序
    weekObjList.sort( key = cmpfun)
    # 获取排序后的最后一项，最大值。
    weekMaxObj = weekObjList[len(weekObjList)-1]

    #获取按月定投的最大利率方式
    monthObjList = []
    # 从1到31选择，
    for i in range(1,32):
        # 获取对应日期的函数返回对象，
        monthObjList.append(monthModel(EveryMoney,i))


    monthObjList.sort(key=cmpfun)

    monthMaxObj = monthObjList[len(monthObjList)-1]

    allIObjList.append(DayinvModel)

    allIObjList.append(weekMaxObj)

    allIObjList.append(monthMaxObj)

    allIObjList.sort(key=cmpfun)

    print("从"+startDate+"至"+endDate+"该基金最优的定投方式是：")

    print(allIObjList[len(allIObjList)-1])

else:
    print('请按要求输入')
# jj1 = monthModel(1000,10)
# print('方式',jj1.invModel,'每期金额',jj1.everyMoney,'投资期数',jj1.numberPeriods,'卖出总金额',jj1.lastProfit,'总投入',jj1.totalInvestment,'利润',jj1.profit)

    # 获取数据的日期一列
# x = fundProfit()
# print(x.getData('150018.SZ','20180101','20200930'))









